package com.tc.banana.framework.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** 
 * 类加载器 加载包下面的所有类
 * @author  wdd 
 * @date 创建时间：2016年4月2日 上午10:46:54 
 */
public class ClassUtil {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);
	
	public static ClassLoader getClassLoad(){
		return Thread.currentThread().getContextClassLoader();
	}
	
	public static Class<?> loadClass(String className){
		return loadClass(className, false);
	}
	
	public static Class<?> loadClass(String className, boolean isInitialized){
		Class<?> cls;
		try {
			cls = Class.forName(className, isInitialized, getClassLoad());
			LOGGER.info("load class " + className + " success");
		} catch (ClassNotFoundException e) {
			LOGGER.error("load class failure", e);
			throw new RuntimeException(e);
		}
		return cls;
	}
	
	/**
	 * 
	 * @param packageName com.tc.banana.framework
	 * @return
	 */
	public static Set<Class<?>> getClassSet(String packageName){
		if ("".equals(packageName.trim())) {
			LOGGER.error("packageName is null");
			throw new RuntimeException("packageName is null");
		}
		Set<Class<?>> classSet = new HashSet<Class<?>>();
		try {
			Enumeration<URL> urls = getClassLoad().getResources(packageName.replace(".", "/"));
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				if (url != null) {
					String protocol = url.getProtocol();
					if (protocol.equals("file")) {
						String packagePath = url.getPath().replaceAll("%20", "");
						addClass(packageName, classSet, packagePath);
					} else if (protocol.equals("jar")) {
						JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
						addJarClass(classSet, jarURLConnection);
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return classSet;
	}

	private static void addJarClass(Set<Class<?>> classSet,
			JarURLConnection jarURLConnection) throws IOException {
		if (jarURLConnection != null) {
			JarFile jarFile = jarURLConnection.getJarFile();
			if (jarFile != null) {
				Enumeration<JarEntry> entries = jarFile.entries();
				while (entries.hasMoreElements()) {
					JarEntry jarEntry = entries.nextElement();
					String jarEntryName = jarEntry.getName();
					if (jarEntryName.endsWith(".class")) {
						String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
						classSet.add(loadClass(className, false));
					}
				}
			}
		}
	}

	private static void addClass(String packageName, Set<Class<?>> classSet, String packagePath) {
		// TODO 判断packageName 和  packagePath 是否为空 
		File [] files = new File(packagePath).listFiles(new FileFilter() {
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
			}
		});
		
		for (File file : files) {
			String fileName = file.getName();
			if (! "".equals(fileName) && file.isFile()){
				String className = packageName + "." + fileName.substring(0, fileName.lastIndexOf("."));
				classSet.add(loadClass(className, false));
				LOGGER.info("add class " + className + " to classSet");
			} else {
				String subPackageName = packageName + "." + fileName;
				String subPackagePath = packagePath + "/" + fileName;
				addClass(subPackageName, classSet, subPackagePath);
			}
		}
	}
	
}
